package dao;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;

import trip.Company;
import trip.HibernateUtil;
import trip.Route;
import trip.Stop;

public class RouteDAOImpl extends GenericDaoImpl<Route> implements RouteDAO{
	public RouteDAOImpl(Class<Route> type) {
		super(type);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Route> getByCompany(Company company) {
		Session session = null;
		List<Route> result = new ArrayList<Route>();
		if (company == null)
			return result;
		try {
			session = HibernateUtil.getFactory().openSession();
			session.beginTransaction();
			Query query = session.createQuery("select distinct t.route "
					+ "from Trip t "
					+ "where t.company = :id");
			query.setLong("id", company.getId());
			result = query.list();
			session.getTransaction().commit();
			return result;
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Route> getActive() {
		Session session = null;
		List<Route> result = new ArrayList<Route>();
		try {
			session = HibernateUtil.getFactory().openSession();
			session.beginTransaction();
			Query query = session.createQuery("select distinct r from Route r where r.active = true ");
			result = query.list();
			session.getTransaction().commit();
			return result;
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<Route> getByStops(Stop departure, Stop arrival) {
		Session session = null;
		List<Route> result = new ArrayList<Route>();
		if (departure == null || arrival == null)
			return result;
		try {
			session = HibernateUtil.getFactory().openSession();
			session.beginTransaction();
			Query query = session.createQuery("select rs1.route "
					+ "from Route_stops rs1, Route_stops rs2  "
					+ "where rs1.route = rs2.route and "
					+ "rs1.stop = :did and rs2.stop = :aid "
					+ "and rs1.stop_number < rs2.stop_number and rs1.route.active = true");
			query.setLong("did", departure.getId());
			query.setLong("aid", arrival.getId());
			result = query.list();
			session.getTransaction().commit();
			return result;
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void create(Route route) {
		Session session = null;
		try {
			session = HibernateUtil.getFactory().openSession();
			session.beginTransaction();
			if (route != null && route.getActive() != null && route.getActive()) {
				Query query = session.createQuery("select r from Route r "
					+ "where r.number = :num");
				query.setLong("num", route.getNumber());
				List<Route> routes = query.list();
				for (Route rt : routes) {
					rt.setActive(false);
					session.update(rt);
				}
			}
			session.save(route);
			session.getTransaction().commit();
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void delete(Route route) {
		Session session = null;
		try {
			session = HibernateUtil.getFactory().openSession();
			session.beginTransaction();
			session.delete(route);
			if (route != null && route.getActive()) {
				Query query = session.createQuery("select r from Route r "
						+ "where r.number = :num order by r.id desc").setMaxResults(1);		
				query.setLong("num", route.getNumber());
				List<Route> lastInactive = query.list();
				if (lastInactive.size() == 1) {
					lastInactive.get(0).setActive(true);
					session.update(lastInactive.get(0));
				}
			}
			session.getTransaction().commit();
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void update(Route route) {
		Session session = null;
		try {
			session = HibernateUtil.getFactory().openSession();
			session.beginTransaction();
			Route tmp = getById(route.getId());
			if (tmp.getNumber() != route.getNumber()) {
				session.update(route);
				Query query = session.createQuery("select r from Route r "
						+ "where r.number = :num order by r.id desc").setMaxResults(1);		
				query.setLong("num", tmp.getNumber());
				List<Route> lastInactive = query.list();
				if (lastInactive.size() == 1) {
					lastInactive.get(0).setActive(true);
					session.update(lastInactive.get(0));
				}
			}
			else
				if (tmp.getActive()) {
					if (tmp.getActive() != route.getActive()) {
						Query query = session.createQuery("select r from Route r "
								+ "where r.number = :num and r.active = false order by r.id desc").setMaxResults(1);		
						query.setLong("num", route.getNumber());
						List<Route> lastInactive = query.list();
						if (lastInactive.size() == 1) {
							lastInactive.get(0).setActive(true);
							session.update(lastInactive.get(0));
						}
					}
					session.update(route);
				}
				else {
					if (tmp.getActive() != route.getActive()) {
						Query query = session.createQuery("select r from Route r "
								+ "where r.number = :num and r.active = true");
						query.setLong("num", route.getNumber());
						List<Route> routes = query.list();
						for (Route rt : routes) {
							rt.setActive(false);
							session.update(rt);
						}
					}
					session.update(route);
				}
			session.getTransaction().commit();
		} finally {
			if (session != null && session.isOpen())
				session.close();
		}
	}
}
